Das neue Workbenchfeeling


Externe Schnittstelle von DirectDos

DirectDosfenster haben eine Schnittstelle f�r externe Programme. Dazu sendet ein fremdes Programm mit der Kennung "TOOL" einen Aktionsrequest an ein oder alle DDFenster.

Derzeit sind definiert:
CDIRChangeDir
INFOSendet Informationen zum betreffenden Fenster
QUITBeende den Task
REPOREPOsitioniere Fenster nach (X-Y) mit der Gr��e (Weite,H�he)
RFRSRefresh zulassen
NORFRefresh sperren
WBRSWB Refresh, der Task soll sein Fenster schlie�en und nach xx Ticks wieder �ffnen
SAVESave zulassen
NOSVSave sperren
ICONIconifizieren
PINGPing-Request
PONGPong-Antwort

Es gibt verschiedene Tags die man verwenden kann, wenn man einem DirectDoswindow eine Nachricht senden will.

  1. DND_SendTask
  2. DND_ID
  3. DND_DragX
  4. DND_DragY
  5. DND_Pointer
  6. DND_DirLock
  7. DND_Reply
  8. DND_Mode
  9. DND_Type
  10. DND_Action
  11. DND_PING
  12. DND_PONG

DND_Tags
TagItemTagData
DND_SendTask Die LoginID des Tools in die MessageQueue von DirectDos, damit die Message auch beantwortet werden kann. Eine Message MU� beantwortet werden mit einem ReplyPacket.
DND_IDDas ist die Kennung von welcher ART Programm die Anweisung kommt.

Kennungen sind "DDOS","DOCK" und "TOOL"

DND_DragX�bergabe des X Anteils einer Koordinate
DND_DragY�bergabe des Y Anteils einer Koordinate
DND_Pointer�bergabe eines Pointerwertes z.b. Zeiger auf einen Speicherblock f�r Daten ( siehe Info )
DND_DirlockLock auf das Director in dem das andere DirectDoswindow operiert
DND_Replywird in das Datenfeld eingetragen um eine Message als erledigt zumarkieren.
DND_ModeHier werden die Qualifier eingetragen die beim Absenden der Message wichtig waren. Das betrifft z.b. Kopie&Move Kommandos von Dateien, aber nur in Verwendung mit DDOS als Kennung f�r DirectDos Windows , bei TOOL steht hier der Befehl an das Window z.B. DND_PING .
DND_TypeFileType der Datei die kopiert oder bewegt werden soll
DND_PINGPING l�sst eine PONG-Nachricht aus, in der die Zeit zu der die PING Nachricht abgearbeitet wurde steht
DND_PONGPONG Nachricht, enth�lt die Uhrzeit zu der Ping abgearbeitet wurde.
eine PONG-Nachricht braucht nicht beantwortet werden. Das w�rde ja nur unn�tigen Traffic im System erzeugen. Sollte eine Anwendung ein PONG bekommen ohne ein PING gesendet zu haben, sollte die Nachricht ignoriert werden.
DND_ActionEnth�lt n�here Infos eines RequestPackets

Wie programmiert man so etwas?

Also der Aufbau ist eigentlich ganz einfach, man sendet eine Nachricht mit GiveData() los und wartet auf die passende Reply via GetData(). Dabei sind immer die Tags : "SendTask" & "ID" auszuf�llen. Es gibt bis Dato drei Kennungen f�r DND_ID: "TOOL" , "DDOS" und "DOCK".

"DOCK"bezeichnet eine Nachricht von DirectDock und sollte auf keinen Fall von jemand anderem benutzt werden.
"TOOL"ist die �bliche Kennung f�r externe Tools um Kommandos an DirectDos zusenden.
"DDOS"ist die Kennung die von DirectDos intern zur Kommunikation verwendet wird

Das "DOCK"-Kommando

Das Dockwindow sendet mit einer DOCKkennung den Zeiger auf Volumename OHNE ":" via DND_Pointer . DirectDos lockt das verzeichnis ein und vollf�rht ein ChangeDirectory() dort hin. Danach sendet es ein DND_REPLY zur�ck.

Tools sollten das Kommando "CDIR" verwenden, zwecks Konsistenz.

Das "DDOS"-Kommandos

DirectDos benutzt diese Kennung f�r interne Kommunikation, also f�r Anweisung f�r Kopies usw. Diese Anweisungen sind Privat und daher nicht von anderen Tools zuverwenden.

SendMail[]:
    Result=DND_GiveData(HitWindow,0,>DragTags:DND_SendTask,*Window|
                                              DND_ID,"DDOS"|
                                              DND_Pointer,*String|
                                              DND_DirLock,*Dirlock|
                                              DND_Mode,*Qualifier|
                                              DND_Type,*Filetype|
                                              Tag_Done,Null)
    ActivateWindow(HitWindow)
    RTS

Dies ist ein Auszug aus dem Source von DirectDos. DND_Pointer enth�lt den Zeiger auf den Namen der zu "was-auch-immer" Datei. DND_Dirlock enth�lt den aktuellen DirectoryLock des sendenen Fensters, so da� der Name keinen Pfad enthalten braucht. Dies spart ne Menge Platz und wird �brigens auch von der Workbench so gehandhabt. DND_MODE enth�lt die Qualifier die beim Absenden der Mail aktuell sind. Hier wird entschieden WAS eigentlich gemacht werden soll. Das tolle daran ist, da� sendene Window hat �berhaupt nichts damit zutun. Es liegt voll in der Entscheidungsfreiheit des Empf�ngers. DND_Type sendet die TypeID des ausgew�hlten Files mit.

F�r alle nicht PreAss-Nutzer sei noch dazu gesagt, da� die "*" angeben ob der Inhalt ( wie in diesem Fall ) oder die Adresse der Variablen in die TagListe �bergeben werden. In C ist das genau umgekehrt, da mu� f�r die Adresse ein "&" eingetragen werden.

Das "TOOL"-Kommandoset

Der typische Aufbau eines Kommandos sieht so aus:

SendRefresh[]: Result=DND_GiveData(HitWindow,0,>ToolTags:DND_SendTask,*Window| DND_ID,"TOOL"| DND_Mode,"RFRS"| Tag_Done,Null) ActivateWindow(HitWindow) WaitMailReply(HitWindow) RTS WaitMailReply[d7]: While (Result=DND_GetDataMsgFromID(Window,d7))=-1 { Delay(10) } DND_FreeData(Result) RTS

Das DND_MODE wird hier anders genutzt, eigentlich hatte ich das ActionTag daf�r vorgesehen, aber wie das so ist, es w�chst ebend. Wenn sich das doch noch �ndern sollte, wird es hier stehen.

REQUESTPINGDiese Nachricht enth�lt keine weiteren Tags, zumindest braucht sie das nicht.
REPLYPONGDiese Nachricht enth�lt die Uhrzeit zu der die Nachricht abgearbeitet wurde
CurrentTime(&Sekunden,&Micros) Result=DND_GiveData(SendTask,0,>PongTags:DND_SendTask,*Window| DND_ID,"DDOS"| DND_Mode,"PONG"| DND_Secs,*Sekunden| DND_Mics,*Micros| Tag_Done,Null) In das ID Feld sollte jeder Sender seine ID eintragen, also DDOS, TOOL usw.
COMMANDREPODND_Pointer zeigt auf einen ausgef�llten PositionArray vom Type Long mit X,Y,W,H,0
REQUESTINFODND_Pointer zeigt auf einen auszuf�llenden Array Type Long X,Y,W,H,COUNT ,
wobei COUNT die Anzahl der Eintr�ge in dem aktuellen Directory des Fensters ist, daran wird der komplette aktuelle Pfadstring angeh�ngt.
COMMANDQUITKeine weiteren Tags
COMMANDCDIRDND_Pointer zeigt auf einen kompletten Pfadstring
COMMANDWBRSKeine weiteren Tags
COMMANDRFRSKeine weiteren Tags
COMMANDNORFKeine weiteren Tags
COMMANDSAVEKeine weiteren Tags
COMMANDNOSVKeine weiteren Tags
COMMANDICONKeine weiteren Tags
COMMANDSELCDND_Pointer enth�lt einen Zeiger auf die zu selektierenden Eintr�ge, alternativ enth�lt DND_Type, den zu selektierenden Filetype
REQUESTREQ!DND_Action enth�lt das eigentliche Kommando

COPYveranlasst das Fenster die selektierten Eintr�ge an den Request-Sender in Form einer normalen DirectDos_prozedur zusenden, im Kopiermodus.
MOVEveranlasst das Fenster die selektierten Eintr�ge an den Request-Sender in Form einer normalen DirectDos_prozedur zusenden, im Movemodus.
NAMESendet alle selektierten Eintr�ge den Namen nach an den Request-Sender, wobei DND_MODE="ANSW" ist und DND_Pointer den Zeiger auf den Namen enth�lt, DND_Dirlock den Lock des aktuellen Verzeihnisses.
DELEOb ein Deletekommando �ber diese Weise sinnvoll ist, sei dahin gestellt, ich �berlegs mir

kursiveTags sind noch nicht implementiert, aber in Planung

Example: REPO {* Array[Long]: PositionArray,0,0,0,0*} {* Incblock: Puffer,100*} SendID=FindTask(0) DND_WhoIsOnline(&Puffer,100) Zeiger1==#Puffer Zeiger1->(DDFenster) While DDFenster#0 { Zeiger==#PositionArray (Left,Top,Width,Height)->Zeiger Result=DND_GiveData(DDFenster,0,>AktionTags:DND_SendTask,*SendID| DND_ID,"TOOL"| DND_Pointer,PositionArray| DND_Mode,"REPO"| Tag_Done,Null) While (Result=DND_GetDataMsgFromID(SendID,DDFenster))=-1 { Delay(10) } DND_FreeData(Result) } RTS

Example: QUIT {* Incblock: Puffer,100*} SendID=FindTask(0) DND_WhoIsOnline(&Puffer,100) Zeiger1==#Puffer Zeiger1->(DDFenster) While DDFenster#0 { Result=DND_GiveData(DDFenster,0,>AktionTags:DND_SendTask,*SendID| DND_ID,"TOOL"| DND_Mode,"QUIT"| Tag_Done,Null) While (Result=DND_GetDataMsgFromID(SendID,DDFenster))=-1 { Delay(10) } DND_FreeData(Result) } RTS


; DirectDos Support : repos ; ; (c) 1998-2001 Cyborg {* Include sys:coder/preass/Options.p *} {* String: Version="$VER: repos demo source (C) CYBORG 1998-2001"*} ; First we setup some structures we need: ; Datastructure is used to comunicate with the different DirectDostasks {* Structure Datastructure,TargetTask(LONG),SendTask(LONG),Data(LONG)*} ; here we store some informations about the windows and chain/store them {* Structure Position1,Left(LONG),Top(LONG),Width(LONG),Height(LONG),POSX(LONG) POSY(LONG),DX(LONG),DY(LONG),Window(LONG),NEXT(LONG)*} ; used to comunicate with the directdos window , we set here the new position ; where the window has to move {* Structure Position(),X(LONG),Y(LONG),W(LONG),H(LONG)*} ; defines a window structure. {* Structure Window,NextWindow(APTR),LeftEdge(WORD),TopEdge(WORD),Width(WORD) Height(WORD),MouseY(WORD),MouseX(WORD),MinWidth(WORD),MinHeight(WORD) MaxWidth(WORD),MaxHeight(WORD),Flags(LONG),MenuStrip(APTR),Title(APTR) FirstRequest(APTR),DMRequest(APTR),ReqCount(WORD),WScreen(APTR) RPort(APTR),BorderLeft(BYTE),BorderTop(BYTE),BorderRight(BYTE) BorderBottom(BYTE),BorderRPort(APTR),FirstGadget(APTR),Parent(APTR) Descendant(APTR),Pointer(APTR),PtrHeight(BYTE),PtrWidth(BYTE),XOffset(BYTE) YOffset(BYTE),IDCMPFlags(LONG),UserPort(APTR),WindowPort(APTR) MessageKey(APTR),DetailPen(BYTE),BlockPen(BYTE),CheckMark(APTR) ScreenTitle(APTR),GZZMouseX(WORD),GZZMouseY(WORD),GZZWidth(WORD) GZZHeight(WORD),ExtData(APTR),UserData(APTR),WLayer(APTR),IFont(APTR) MoreFlags(LONG)*} ; some const which Drag`n`Drop and DirectDos use. {* Const DND_Base=Tag_User DND_SendTask=DND_Base+1 DND_ID=DND_Base+2 DND_DragX=DND_Base+3 DND_DragY=DND_Base+4 DND_Pointer=DND_Base+5 DND_Dirlock=DND_Base+6 DND_Reply=DND_Base+7 DND_Mode=DND_Base+8 DND_Type=DND_Base+9 DND_Action=DND_Base+10*} ; WaitMailReply: ; ; We wait for the reply message that has to send from a directdos window ; to say : "did it" . We have to check if the window was closed, this is ; possible , because DirectDos makes multitasking. ; our id is "-1" , so we have to wait for new data for id -1. If no ; data(message) arrived , wait a bit and then retry it. ; ; It is possible to change this routine to a simpler construct, which returns ; immediatly, if no data arrived. This won`t matter that much , because ; the arriving messages will be stored in a queue . You had to add a routine ; to empty the queue! ; ; Additional remark: We can use this construct because no other task would send us ; a message so the REPLY message is the requested one! Keep this ; in mind! or change it to the NEW Function GetDataMsgFromID() WaitMailReply[a0]: {* Stackframe HitWindow=a0,Taskdata=#0*} If DND_IsOnline(Hitwindow)#0 { While (Result=DND_GetdatamsgfromID(-1,hitwindow))=-1 { Delay(4) If DND_IsOnline(Hitwindow)=0 breakwhile } If result#-1 { DND_FreeData(Result) } } {* unframeReturn *} ; SendRePos: ; ; if the window is still existing , we send a message to the windowtask. ; we have to activate the window to signal , that the task checks it messagequeue. ; At last we have to wait for the replymessage. SendRePos[a0,d0,d1,d2,d3]: {* Stackframe HitWindow=a0,X=d0,Y=d1,w=d2,h=d3*} If DND_IsOnline(Hitwindow)#0 { X=>position.X Y=>position.Y W=>position.W H=>position.H Result=DND_GiveData(HitWindow,0,>Drag3Tags:DND_SendTask,-1| DND_ID,"TOOL"| DND_Mode,"REPO"| DND_Pointer,Position| Tag_Done,Null) ActivateWindow(HitWindow) WaitMailReply(Hitwindow) } {* UnFrameReturn *} ; SendNoReFresh: ; ; works like SendRePos. But it sends not a reposition message , instead we ; turn off the auto refresh. Normally a directdos window will refresh after ; moving or changing size. To avoid this while moving , we turn it off. ; SendNORefresh[a0]: {* Stackframe HitWindow=a0*} If DND_IsOnline(Hitwindow)#0 { Result=DND_GiveData(HitWindow,0,>Drag2Tags:DND_SendTask,-1| DND_ID,"TOOL"| DND_Mode,"NORF"| Tag_Done,Null) ActivateWindow(HitWindow) WaitMailReply(HitWindow) } {* UnFrameReturn *} ; SendReFresh: ; ; works like SendRePos. But it sends not a reposition message , instead we ; turn on the auto refresh. Normally a directdos window will refresh after ; moving or changing size. ; SendRefresh[a0]: {* Stackframe HitWindow=a0*} If DND_IsOnline(Hitwindow)#0 { Result=DND_GiveData(HitWindow,0,>Drag1Tags:DND_SendTask,-1| DND_ID,"TOOL"| DND_Mode,"RFRS"| Tag_Done,Null) ActivateWindow(HitWindow) WaitMailReply(Hitwindow) } {* UnFrameReturn *} ; InsertNewWindow: ; ; Chain new windowdata to the list , which starts with the second entry. The real ; root entry is empty and unused. ; ; If the nextfield in the entry is empty, we allocate a new entrystructure and ; store the data in it and chain it the last entry. InsertNewWindow[a0,d0,d1,d2,d3,d4,d5,d6,d7]: {* Stackframe last,Window=a0,Window1,left=d0,top=d1,width=d2,height=d3,posx=d4,posy=d5,dx=d6,dy=d7,next*} Next=.lPosition1.next(Root) Last==Root While Next#0 { Last==Next Next=.lPosition1.next(Next) } next=malloc(sizeof(position1)) next=>Last.Position1.next posx=>next.Position1.posx posy=>next.Position1.posy dx=>next.Position1.dx dy=>next.Position1.dy window=>next.Position1.window left=>next.Position1.left top=>next.Position1.top width=>next.Position1.width height=>next.Position1.height 0=>next.Position1.next {* UnframeReturn *} ; GetWindowData: ; ; the parse throu all entries and compare the given windowid with the stored ; one. if it matchs , we give the needed informations back. GetWindowData[a0]: {* Stackframe Window=a0,Window1,left,top,width,height,next*} Next=.lPosition1.next(Root) While Next#0 { window1=.lPosition1.Window(Next) if window1=window { left=.lPosition1.left(Next) top=.lPosition1.top(Next) Width=.lPosition1.width(Next) Height=.lPosition1.height(Next) {* UnframeReturnM Left,Top,Width,Height*} } Next=.lPosition1.next(Next) } {* UnframeReturnM 0,0,0,0*} ; UpdateWindow: ; ; the parse throu all entries and compare the given windowid with the stored ; one. if it matchs , we update the important fields. UpdateWindow[a0,d0,d1,d2,d3]: {* Stackframe Window=a0,Window1,posx=d0,posy=d1,dx=d2,dy=d3,next*} Next=.lPosition1.next(Root) While Next#0 { window1=.lPosition1.Window(Next) if window1=window { posx=>Next.Position1.posx posy=>Next.Position1.posy dx=>Next.Position1.dx dy=>next.Position1.dy {* UnframeReturn *} } Next=.lPosition1.next(Next) } {* UnframeReturn *} ; GetPosData: ; ; the parse throu all entries and compare the given windowid with the stored ; one. if it matchs , we give the needed informations back. GetPosData[a0]: {* Stackframe Window=a0,Window1,posx,posy,dx,dy,width,height,next*} Next=.lPosition1.next(Root) While Next#0 { window1=.lPosition1.Window(Next) if window1=window { posx=.lPosition1.posx(Next) posy=.lPosition1.posy(Next) dx=.lPosition1.dx(Next) dy=.lPosition1.dy(Next) Width=.lPosition1.width(Next) Height=.lPosition1.height(Next) {* UnframeReturnM posx,posy,dx,dy,Width,Height*} } Next=.lPosition1.next(Next) } {* UnframeReturnM 0,0,0,0,0,0*} start: {* IncVar: window*} ; we get some memory to store the different windowids ( max. 250 ) mem=malloc(1000,#MEMF_CLEAR) ; we need the screensize to get the borders set. Screen=.l60(IntuitionBase) MaxW=.w12(Screen) MaxH=.w14(Screen) ; the first ( dummy ) entry of our chained list is allocated here root=malloc(sizeof(position1)) ; Make sure its safe to use. 0=>root.Position1.next 0=>root.Position1.Window ; Get the informations from the drag`n`drop-queue. DND_WhoisOnline(mem,1000) ; for each window we got, we have to do some inits Zeiger==mem Zeiger->(Window) While window#0 { ; prevent window from refreshing SendNORefresh(Window) ; bring to front, so everyone can see it. WindowtoFront(Window) ; get the windowinformation Left=.wWindow.Leftedge(Window) Top=.wWindow.Topedge(Window) Width=.wWindow.Width(Window) Height=.wWindow.height(Window) dx==4 dy==2 ; sort data in InsertNewWindow(Window,Left,Top,Width,Height,Left,Top,dx,dy) Zeiger->(Window) } Zeiger==mem Zeiger->(Window) ; if we have at least one window we can start if window#0 { ; this is an endless loop which could be canceld by pressing CTRL-C ; of the closing of one window. Repeat Zeiger==mem Zeiger->(Window) While window#0 { ; ask if the have to break in case someone pressed CTRL-C sigs=SetSignal(0,0) If Sigs&$f000#0 breakwhile ; if a window is no longer present , skip it. If DND_IsOnline(Window)#0 { ; Get window data from chained list (posx,posy,dx,dy,width,height)=GetPosData(window) ; Send new position to window SendRePos(Window,posx,posy,Width,Height) ; calculate new position posx==posx+dx posy==posy+dy ; border check , we reverse the direction if we hit one border ; this is be done, by negate the delta of X and Y , which is added above ; to the old position. The following calculation corrects the border overrun. if posx<=0 or posx+width>maxW { dx==-dx posx==posx+dx } if posy<=0 or posy+height>maxH { dy==-dy posy==posy+dy } ; the new position has to be stored in the chained list. UpdateWindow(window,posx,posy,dx,dy) } ; get next window from array. Zeiger->(Window) } ; if we got a break from the inner while , we have to break the outer while ; to. until Sigs&$f000#0 } ; the next lines will reposition the window at it`s old place and ; sets it back to REFRESH mode. Zeiger==mem Zeiger->(Window) While window#0 { (Left,Top,width,height)=GetWindowdata(window) SendRePos(Window,left,top,Width,Height) SendRefresh(Window) Zeiger->(Window) } {* Return *}


DirectDos & his Homepage designed by I.P.S. © 1999